using SmartCommunity.Models;
using Mapster;
using Microsoft.EntityFrameworkCore;

namespace SmartCommunity.Services.Community
{
    /// <summary>
    /// 服务类：
    /// </summary>
    public class RoomService : BaseService<RoomEntity>
    {
        #region 构造函数
        protected readonly SCDBContext ctx;
        public RoomService(SCDBContext ctx)
        {
            this.ctx = ctx;
        }
        #endregion

        #region 数据查询 
        /// <summary>
        /// 分页查询
        /// </summary>
        public async Task<PageResult<RoomDto>> FindPagedList(RoomQuery roomQuery, Pager pager, LoginUser user)
        {
            var query = ctx.Rooms.Include(a => a.Building).ThenInclude(t => t.Area).AsNoTracking().Where(roomQuery.GetQueryExpression());
            var data = await FindPagedList(query, pager, o => o.OrderByDescending(t => t.CreatedTime));
            var pageDto = data.Map(o => o.Adapt<RoomDto>());
            await MergeRoomEnums(pageDto.DataList);
            return pageDto;
        }

        /// <summary>
        /// 根据ID查询
        /// </summary>
        public async Task<RoomDto> FindRoomById(Guid roomId)
        {
            var entity = await FindById(roomId);
            return entity.Adapt<RoomDto>();
        }

        /// <summary>
        /// 根据ID查询实体类
        /// </summary>
        private async Task<RoomEntity> FindById(Guid id)
        {
            return await ctx.Rooms.SingleOrDefaultAsync(a => a.RoomId == id)
                ?? throw new NotFoundException($"找不到指定的,Id:{id}");
        }

        /// <summary>
        /// 查询建筑树，包含社区和小区
        /// </summary>
        public async Task<IEnumerable<SelectOption>> GetBuildingTree()
        {
            var buildings = await ctx.Communities.Include(a => a.Areas).ThenInclude(t => t.Buildings).ToListAsync();
            var nodes = new List<SelectOption>();
            foreach (var community in buildings)
            {
                var node = new SelectOption(community.CommunityId, community.CommunityName, community.Disabled) { Icon = "mdi-city", Selectable = false };
                if (community.Areas.Count > 0)
                {
                    foreach (var area in community.Areas)
                    {
                        var areaNode = new SelectOption(area.AreaId, area.AreaName, area.Disabled) { Icon = "mdi-home-city", Selectable = false };
                        if (area.Buildings.Count > 0)
                        {
                            areaNode.Children.AddRange(ConvertTree(area.Buildings.Where(a=>a.Parent==null), true));
                        }
                        node.Children.Add(areaNode);
                    }
                }
                nodes.Add(node);
            }
            return nodes;
        }


        private List<SelectOption> ConvertTree(IEnumerable<BuildingEntity> buildings, bool topLevel)
        {
            var icon = topLevel ? "mdi-office-building" : "mdi-office-building-outline";
            var nodes = new List<SelectOption>();
            var tmp = buildings.Select(a =>
            {
                var node = new SelectOption(a.BuildingId, a.BuildingName, false) { Icon = icon };
                if (a.Children.Any())
                {
                    node.Selectable = false;
                    node.Children = ConvertTree(a.Children, false);
                }
                else node.Selectable = true;
                return node;
            });
            nodes.AddRange(tmp);
            return nodes;
        }

        private async Task MergeRoomEnums(IEnumerable<RoomDto> rooms)
        {
            var dicts = await ctx.Dicts.Include(a => a.DictItems).Where(a => a.DictType.StartsWith("Room")).ToListAsync();
            var stateMap = dicts.SingleOrDefault(a => a.DictType == "RoomState")!.DictItems.ToDictionary(k => k.DictValue, v => v.DictLabel);
            var typeMap = dicts.SingleOrDefault(a => a.DictType == "RoomType")!.DictItems.ToDictionary(k => k.DictValue, v => v.DictLabel);
            var usageMap = dicts.SingleOrDefault(a => a.DictType == "RoomUsage")!.DictItems.ToDictionary(k => k.DictValue, v => v.DictLabel);
            var decoMap = dicts.SingleOrDefault(a => a.DictType == "RoomDeco")!.DictItems.ToDictionary(k => k.DictValue, v => v.DictLabel);
            foreach (var d in rooms)
            {
                if (stateMap != null && stateMap.TryGetValue(d.RoomState.ToString(), out var ln)) d.RoomStateName = ln;
                if (typeMap != null && typeMap.TryGetValue(d.RoomType.ToString(), out var tn)) d.RoomTypeName = tn;
                if (usageMap != null && usageMap.TryGetValue(d.RoomUsage.ToString(), out var un)) d.RoomUsageName = un;
                if (decoMap != null && decoMap.TryGetValue(d.RoomDeco.ToString(), out var dn)) d.RoomDecoName = dn;
            }
        }
        #endregion

        #region 增 删 改
        /// <summary>
        /// 新增
        /// </summary>
        public async Task<RoomDto> CreateRoom(RoomDto dto, LoginUser user)
        {
            // 新建对象
            var entity = new RoomEntity();
            // 复制属性
            await CopyDtoToEntity(dto, entity, user, true);
            var building = await ctx.Buildings.Include(a => a.Parent).SingleOrDefaultAsync(a => a.BuildingId == dto.BuildingId);
            if (building != null)
            {
                entity.RoomCode = (building.Parent==null?"":building.Parent.BuildingNo+"-")+building.BuildingNo+"-"+dto.RoomNo;
            }
            // 执行保存
            ctx.Rooms.Add(entity);
            await ctx.SaveChangesAsync();
            // 返回Dto
            return entity.Adapt<RoomDto>();
        }

        /// <summary>
        /// 更新
        /// </summary>
        public async Task UpdateRoom(RoomDto dto, LoginUser user)
        {
            // 原始数据
            var entity = await FindById(dto.RoomId);
            // 更新字段
            await CopyDtoToEntity(dto, entity, user, false);
            // 执行更新
            await ctx.SaveChangesAsync();
        }

        /// <summary>
        /// 复制dto属性到实体字段
        /// </summary>
        private async Task CopyDtoToEntity(RoomDto dto, RoomEntity entity, LoginUser user, bool isNew)
        {
            //TODO 检查数据重复
            if (await ctx.Rooms.AnyAsync(a => a.RoomId != dto.RoomId && (a.BuildingId == dto.BuildingId && a.RoomNo == dto.RoomNo)))
            {
                throw new MessageException("当前楼已存在相同房号的房间");
            }
            entity.BuildingId = dto.BuildingId;
            entity.RoomNo = dto.RoomNo;
            entity.RoomCode = dto.RoomCode;
            entity.RoomFloor = dto.RoomFloor;
            entity.RoomUsage = dto.RoomUsage;
            entity.RoomType = dto.RoomType;
            entity.RoomState= dto.RoomState;
            entity.RoomDeco = dto.RoomDeco;
            entity.BuildArea = dto.BuildArea;
            entity.UsageArea = dto.UsageArea;
            entity.IsIdle = dto.IsIdle;
            entity.Manager = dto.Manager;
            entity.ManagerTel = dto.ManagerTel;
            entity.Remark = dto.Remark;

            // 记录操作人
            if (isNew)
            {
                entity.CreatedBy = user.Username;
                entity.CreatedTime = DateTime.Now;
            }
            entity.UpdatedBy = user.Username;
            entity.UpdatedTime = DateTime.Now;
        }

        /// <summary>
        /// 根据ID删除
        /// </summary>
        public async Task DeleteByIds(IEnumerable<Guid> ids, LoginUser user)
        {
            var rooms = await ctx.Rooms.Where(a => ids.Contains(a.RoomId)).ToListAsync();
            if (rooms.Count != ids.Count())
            {
                throw new MessageException("查询出的数据和传入的ID不匹配，请刷新后再试。");
            }
            //TODO 判断是否能删除
            foreach (var entity in rooms)
            {
                ctx.Rooms.Remove(entity);
            }
            // 提交事务
            await ctx.SaveChangesAsync();
        }


        #endregion
    }
}
